package top.frsf.rpc.code.decode;

import cn.hutool.json.JSONUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.CorruptedFrameException;
import lombok.extern.slf4j.Slf4j;
import top.frsf.rpc.constants.RpcConstants;
import top.frsf.rpc.protocol.RpcMessage;
import top.frsf.rpc.protocol.head.RpcHeader;
import top.frsf.rpc.protocol.body.RpcReqBody;
import top.frsf.rpc.protocol.body.RpcRespBody;

import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * RPC 消息解码器
 *
 * @author He Kuntao
 * @since 2025/7/2 10:28
 */
@Slf4j
public class RpcMessageDecoder extends ByteToMessageDecoder {
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> list) throws Exception {
        // 1. 检查最小可读长度 (魔数2字节 + 剩余头16字节)
        if (byteBuf.readableBytes() < 18) {
            return;
        }

        // 2. 检查魔数
        checkMagic(byteBuf);

        // 3. 读取协议头（LengthFieldBasedFrameDecoder 已保证数据完整）
        RpcHeader header = readHeader(byteBuf);
        log.info("接收到请求头：{}", header);
        RpcMessage<Object> message = new RpcMessage<>();
        message.setHeader(header);

        // 4. 读取消息体
        byte[] bodyData = new byte[header.getBodyLength()];
        byteBuf.readBytes(bodyData);
        String json = new String(bodyData, StandardCharsets.UTF_8);
        log.info("接收到请求体：{}", json);

        // 5.反序列化body
        if (RpcConstants.FLAG_REQUEST == header.getFlags()) {
            RpcReqBody reqBody = JSONUtil.toBean(new String(bodyData, StandardCharsets.UTF_8), RpcReqBody.class);
            message.setBody(reqBody);
        } else {
            RpcRespBody respBody = JSONUtil.toBean(new String(bodyData, StandardCharsets.UTF_8), RpcRespBody.class);
            message.setBody(respBody);
        }
        list.add(message);
    }

    /**
     * 检查魔数
     *
     * @param byteBuf 字节缓冲区
     */
    private static void checkMagic(ByteBuf byteBuf) {
        byteBuf.markReaderIndex();
        short magic = byteBuf.readShort();
        if (magic != RpcConstants.MAGIC) {
            throw new CorruptedFrameException("Invalid magic number: 0x" + Integer.toHexString(magic & 0xFFFF));
        }
        byteBuf.resetReaderIndex(); // 重置到标记位置（包含魔数）
    }


    /**
     * 读取协议头
     *
     * @param byteBuf 字节缓冲区
     * @return RPC 协议头
     */
    private RpcHeader readHeader(ByteBuf byteBuf) {
        return RpcHeader.builder()
                .magic(byteBuf.readShort())
                .version(byteBuf.readByte())
                .flags(byteBuf.readByte())
                .serialType(byteBuf.readByte())
                .status(byteBuf.readByte())
                .requestId(byteBuf.readLong())
                .bodyLength(byteBuf.readInt())
                .build();
    }
}
